Repository navigation
Conversation
Task: fn-291-preserve-successful-claude-reviews-with.1
Merge the five original fn-291 commits onto upstream main without rewriting their provenance. Preserve the Claude correction and regression tests reviewed at 57eaa17; retain the upstream 8.5.2 changelog and regenerate the tracker manifest canonically. Task: fn-291-preserve-successful-claude-reviews-with.1
There was a problem hiding this comment.
🟡 Changes recommended
A failed ladder-floor execution is still cached, causing later reviews to bypass stronger models and retry the failed floor.
1 open finding
What changed in this PR
This PR hardens Claude review result classification, preserving valid warning-bearing reviews while rejecting malformed or failed executions.
Changes:
- Prioritizes valid zero-exit Claude result envelopes over stderr diagnostics.
- Adds regression coverage for review finalization, failures, fallback, caching, and sessions.
- Updates transport documentation, generated mirrors, changelog, and Flow records.
| File | Description |
|---|---|
plugins/flow-next/scripts/flowctl.py |
Implements strict Claude result and exit classification. |
plugins/flow-next/tests/test_claude_review_commands.py |
Tests official review handlers and failure accounting. |
plugins/flow-next/tests/test_model_resolution.py |
Updates the stderr-only fallback fixture. |
plugins/flow-next/scripts/flowctl_tracker/MANIFEST.json |
Refreshes the generated source hash. |
plugins/flow-next/docs/flowctl.md |
Documents Claude transport and fallback rules. |
plugins/flow-next/docs/troubleshooting.md |
Adds operator guidance for warning-bearing results. |
plugins/flow-next/codex/docs/flow-next/flowctl.md |
Mirrors the runtime documentation. |
plugins/flow-next/codex/docs/flow-next/troubleshooting.md |
Mirrors troubleshooting guidance. |
CHANGELOG.md |
Records the user-facing fix. |
.flow/specs/fn-291-preserve-successful-claude-reviews-with.md |
Defines requirements and boundaries. |
.flow/specs/fn-291-preserve-successful-claude-reviews-with.json |
Records specification state and review history. |
.flow/tasks/fn-291-preserve-successful-claude-reviews-with.1.md |
Captures completion evidence. |
.flow/tasks/fn-291-preserve-successful-claude-reviews-with.1.json |
Records task metadata and status. |
🧠 Review effort: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Require exit-zero fallback executions before caching or reporting a temporary model resolution. Invalidate failed cached choices while preserving terminal errors and the existing bounded unavailable-model ladder. Reproduce the pre-existing PR gmickel#546 finding with mocked CLI regressions across all four adapters. Task: fn-292-avoid-caching-failed-fallback-review.1
Merge upstream/main e01de49, including gmickel#547 and its 8.5.3 release, without rewriting the published fn-291/fn-292 history. Preserve the Unreleased entry and regenerate the tracker manifest canonically. The code is the automatic merge of the existing corrections. Parent AST comparisons preserve the Claude terminal-result, failed fallback-cache, and open-receipt fixes without additional behavior from conflict resolution. Historical SHIP receipts remain linked to their original snapshots. Validation: 4012 offline unit tests with 7 skips and no failures/errors; 289 focused tests; Ruff 0.16.0, manifest, Codex mirror, documentation anchors, Flow validation and Git checks passed.
Merge upstream main f360d3a without rewriting the published branch. Resolve only the Unreleased changelog placement and regenerate the tracker manifest. Claude terminal parsing, execution and fallback-cache functions remain AST-identical to 211e900; regression tests are unchanged. Validation: 4071 tests, 0 failures, 0 errors, 7 skips; Ruff, mirror, manifest, anchors and Git checks pass. Historical review receipts retain their original commit ranges.
|
Thanks for the review. I corrected the documentation findings: the troubleshooting example now matches the emitted fallback warning and closes its parenthetical; the fallback description no longer suggests the stderr tag rescues a non-matching error envelope; and the changelog now records successful-only fallback caching. The Codex documentation mirrors were regenerated. I left the non-blocking P3 implementation cleanup suggestions unchanged. They identify redundant checks and internal diagnostic state, but no incorrect user-visible behavior; changing the classifier or dispatch state was not needed to address the reported documentation defects. Validation after merging upstream 9.2.0: the focused Claude and model-resolution suites passed (27 and 67 tests), the full suite passed (4,083 tests, zero failures or errors, 7 skipped), and Ruff, the generated Codex mirror check, and the tracker manifest check passed. After the documentation-only corrections, mirror generation and its check, Ruff, and |
* chore(flow): capture fn-310 and fn-311 for the 9.5.1 patch Claude-Session: https://claude.ai/code/session_01HdQUZUkJsRZSWh3DgKUcLM * fix: Copilot review diff, GitHub label cap and non-GitHub origin probe - Copilot primary reviews get the reviewed diff by path, as Claude does (#529); the helper is now backend-neutral. - The GitHub wire label verb cuts names to GitHub's 50-character cap, so long flow:<spec-id> back-references land (#578). - A non-GitHub origin is "no PR forge" for the route probes, so flow --auto routes from the lifecycle (#583); make-pr stops NEEDS_HUMAN before any close or push. Task: fn-310-review-diff-tracker-label-and-gitlab.1 Co-authored-by: Julien Carosi <jcarosi@gmail.com> Co-authored-by: NefelibateLG <3453510037@qq.com> Claude-Session: https://claude.ai/code/session_01HdQUZUkJsRZSWh3DgKUcLM * fix(review): keep valid Claude reviews and cache only successful fallbacks A zero-exit Claude success envelope is the review even when stderr carries the [claude-code:unrecognized_model] diagnostic, which Claude Code emits for working gateway aliases. Malformed envelopes, error envelopes, non-zero exits and timeouts never supply a verdict. The model-resolution cache records a fallback or floor only after it ran successfully, and drops a cached choice whose run fails. Adapted from PR #546. Task: fn-310-review-diff-tracker-label-and-gitlab.1 Co-authored-by: Julien Carosi <jcarosi@gmail.com> Claude-Session: https://claude.ai/code/session_01HdQUZUkJsRZSWh3DgKUcLM * docs: Copilot diff delivery and the 9.5.1 changelog entries Task: fn-310-review-diff-tracker-label-and-gitlab.1 Claude-Session: https://claude.ai/code/session_01HdQUZUkJsRZSWh3DgKUcLM * chore(flow): review with codex gpt-6.1-sol at high Matches the reviewer tier in the repo's model-routing block. Claude-Session: https://claude.ai/code/session_01HdQUZUkJsRZSWh3DgKUcLM * fix: make-pr checks origin itself; Cursor gets the diff by path Review round 1 fixes: - make-pr's forge guard reads origin's host (SSH aliases via ssh -G) and asks gh for a token for it, before the install and auth checks. A GitLab origin now stops NEEDS_HUMAN with no gh login, with GH_TOKEN set, and beside a GitHub upstream; GitHub Enterprise hosts gh is logged in to pass. - Cursor's ask mode blocks shell where no OS sandbox exists (Windows), so Cursor primary reviews also get the diff by path. Probed on Linux: ask mode ran git hash-object, and read a gitignored .flow/tmp file with file tools. Task: fn-310-review-diff-tracker-label-and-gitlab.1 Claude-Session: https://claude.ai/code/session_01HdQUZUkJsRZSWh3DgKUcLM * chore(flow): task receipt fn-310-review-diff-tracker-label-and-gitlab.1 Claude-Session: https://claude.ai/code/session_01HdQUZUkJsRZSWh3DgKUcLM * chore(flow): close fn-310-review-diff-tracker-label-and-gitlab * Address PR review feedback (#589) - make-pr's origin-host parser accepts userless scp remotes (host:path), so an SSH alias such as gh-work:o/r.git resolves through ssh -G instead of stopping NEEDS_HUMAN. Claude-Session: https://claude.ai/code/session_01HdQUZUkJsRZSWh3DgKUcLM --------- Co-authored-by: Julien Carosi <jcarosi@gmail.com> Co-authored-by: NefelibateLG <3453510037@qq.com>
|
Thanks for the careful work here, especially the offline repro with the fake Claude process. It made the bug easy to confirm on main. Both fixes are in #589 for 9.5.1. A zero-exit success envelope now counts as the review whatever stderr says, and the model-resolution cache records a fallback only after it ran successfully. I applied your flowctl change and tests, then shortened the classification in You're credited in the changelog and as co-author. Closing this in favour of #589. |

Why
Claude Code can emit
[claude-code:unrecognized_model]for a working gateway alias while returning a successful JSON result. Its official error reference describes this as a diagnostic that does not stop the request or switch models.Upstream 9.3.2 (
272a4020) still classifies the stderr marker as model unavailability before honoring the successful result. Flow discards the review text and rejects the result, or can enter the availability ladder when the model was not explicitly pinned.Review focus
Start with
run_claude_execand_parse_claude_resultinplugins/flow-next/scripts/flowctl.py, then the handler-level regressions intest_claude_review_commands.py.A valid zero-exit success envelope takes precedence over the warning. Malformed envelopes, error results, nonzero process exits and timeouts still cannot supply a verdict. Genuine unavailable-model responses retain the existing bounded resolution behavior, and explicit model selections never silently change.
This existing PR also carries its previously reviewed shared fallback-cache correction: only successful fallback executions are cached, and failed cached selections are invalidated. The latest update adds two Claude regressions and merges upstream 9.3.2; it adds no new backend behavior, configuration or fallback.
Needs you
Repository-wide
flowctl validate --allstill reports 23 legacy errors infn-16-ugnandfn-24-codex-first-class-citizen-native-plugin. The error set is identical on unmodified upstream 9.3.2. These historical records are outside this correction.The upstream maintainer retains the merge decision. No hosted model review was requested.
Reproduce without a provider
The fake Claude process returns:
Run the real-handler regression:
With the regression transplanted onto unmodified upstream
272a4020, Flow returns 2 instead of the expected 0. On this branch it writes a SHIP receipt, retainsclaude:gateway-custom-model:medium, dispatches exactly once and creates no availability-cache entry. No LLM is invoked.The negative cases cover malformed JSON and wrong-typed fields, genuine model errors, nonzero exits, and a timeout carrying partial SHIP output plus the warning. Failed attempts publish no verdict or new valid receipt, refund their reservation and do not silently fall back.
Verified
272a4020, green with the correction.python3 scripts/run_tests_parallel.py: 4,082 tests across 218 files; 0 failures, 0 errors, 7 skipped.uvx ruff@0.16.0 check ., tracker manifest freshness, Codex mirror freshness, documentation anchors andgit diff --check: passed.codex:gpt-6.1-sol:xhigh: SHIP, no findings, finalized for candidatea0c9cab5against upstream272a4020. The reviewer completed its inspection and in-memory checks; its read-only sandbox prevented the temporary-directory suites, which passed in the coordinator's full run.The historical Flow records remain bound to their recorded snapshots. The new review covers the current integrated candidate. This PR contains no private incident logs or application changes, and does not modify shared installations or permanent model routing.
Archived FN-13 offline replay
The original Claude JSON stdout was not retained. An offline replay placed the preserved complete result text and warning into a synthetic success envelope; the installed Flow-Next 9.1.1 adapter and unmodified upstream 9.3.2 rejected it, while PR head
a0c9cab5accepted it after one mocked dispatch. Synthetic negative cases covered genuine 404 model errors, nonzero transport exits, malformed JSON, missing fields, and error envelopes. This replay invoked no LLM and created no official review receipt.